#ifndef SymbolTable_H
#define SymbolTable_H
#include "ASTnode.h"
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <map>
#include <memory>
#include <tuple>
#include <unordered_set>
#include <set>
#include <iterator>
using namespace std;
namespace name_type {
    enum class TYPE {
        CHAR,
        INT,
        FLOAT,
        BOOL,
        STRING,
        NEXIST
    };
    enum class CLASS {
        CONST,
        VARIABLE,
        ARRAY,
        RECORD,
        FUNCTION,
        PROCEDURE,
        NEXIST
    };
    enum class TypeForm {
        STANDARD,
        RECORD,
        ARRAY
    };
}
using name_type::TYPE;
using name_type::CLASS;
using name_type::TypeForm;

typedef pair<string, string> PSS;
typedef pair<int, int> PII;
typedef pair<string,int> PSI;
typedef pair<CLASS, int> PCI;
typedef pair<TYPE, string> PTS;
typedef pair<PTS, int> PTSI;


class ReturnValue{
public:
    TYPE typeName;       //取值为 int float bool char null 如果是 null说明是过程 如果是其他说明是函数
    string nameInComputer; 
    int line;
};

class Sym_parameter{
public:
    string name;           //变量本来名字
    TYPE typeName;         
    bool isReference;      //是否是引用 1就表示是 0 表示不是
    string nameInComputer; 
};

class Sym_constVariable{
public:
    string name;         //常量本来名字
    TYPE typeName;
    string value;
    bool is_minus;
    int line;
    string nameInComputer;
};

class Sym_variable{
public:
    TYPE typeName;   
    string name;           //变量本来名字
    string nameInComputer; 
    int line;
};

// 定义带有符号(变量)的偏移
class Offset {
public:
    // 定义值为多项式形式的偏移量，即 a + bt1 + ct2 + dt3 + ....
    // a对应的cst，其他对应coe
    std::map<std::string, size_t> coe;
    size_t cst;

    Offset(): coe(std::map<std::string, size_t>()), cst(0) {

    }

    Offset(const std::map<std::string, size_t> &_coe, size_t _cst): coe(_coe), cst(_cst) {

    }

    Offset(std::map<std::string, size_t> &&_coe, size_t _cst): coe(std::move(_coe)), cst(_cst) {

    }

    Offset& operator += (size_t s) {
        this->cst += s;

        return *this;
    }

    Offset& operator += (const pair<std::string, size_t> &val) {
        auto it = coe.find(val.first);
        if (it == coe.end()) {
            coe.insert(val);
        }
        else {
            it->second += val.second;
        }
        return *this;
    }

    Offset& operator += (pair<std::string, size_t> &&val) {
        auto it = coe.find(val.first);
        if (it == coe.end()) {
            coe.insert(std::move(val));
        }
        else {
            it->second += val.second;
        }
        return *this;
    }

    Offset& operator += (const vector<pair<std::string, size_t>> &vals) {
        for (const auto val : vals) {
            auto it = coe.find(val.first);
            if (it == coe.end()) {
                coe.insert(val);
            }
            else {
                it->second += val.second;
            }
        }
        return *this;
    }

    Offset& operator += (vector<pair<std::string, size_t>> &&vals) {
        for (int i = 0; i < vals.size(); i++) {
            auto it = coe.find(vals[i].first);
            if (it == coe.end()) {
                coe.insert(std::move(vals[i]));
            }
            else {
                it->second += vals[i].second;
            }
        }
        return *this;
    }

    Offset& operator += (const Offset &rhs) {
        this->cst += rhs.cst;
        for (auto val : rhs.coe) {
            auto it = coe.find(val.first);
            if (it == coe.end()) {
                coe.insert(val);
            }
            else {
                it->second += val.second;
            }
        }

        return *this;
    }
};

class SymType{
public:
    SymType(): type_size(0) {}
    virtual bool operator == (const SymType &b) const = 0;
    virtual bool operator != (const SymType &b) const {
        return !(*this == b);
    }
    virtual TypeForm get_type_form() const = 0;
    virtual void set_size() = 0;
    virtual size_t get_size() const {
        return this->type_size;
    }

    virtual void set_align_size() = 0;

    size_t get_align_size() const {
        return align_size;
    }

    // 返回pair<offset, type_size>
    virtual pair<Offset, TYPE> get_var(vector<string>::iterator begin, vector<string>::iterator end) const = 0; 

    // string id;
    size_t type_size;
    size_t align_size;
};

class SymStdType: public SymType {
public:
    SymStdType(): SymType(), typeName(TYPE::NEXIST) {

    }

    SymStdType(TYPE type): typeName(type) {
        this->set_size();
        this->set_align_size();
    }

    virtual bool operator == (const SymType &b) const final {
        return b.get_type_form() == TypeForm::STANDARD && this->equal_to(dynamic_cast<const SymStdType&>(b));
    }

    bool equal_to(const SymStdType& b) const {
        return b.typeName == this->typeName;
    }

    void set_align_size() final {
        align_size = type_size;
    }

    virtual TypeForm get_type_form() const final{
        return TypeForm::STANDARD;
    }
    virtual void set_size() override {
        switch (typeName) {
            case TYPE::CHAR:
                type_size = 1;
                break;
            case TYPE::INT:
                type_size = 4;
                break;
            case TYPE::FLOAT:
                type_size = 8;
                break;
            case TYPE::BOOL:
                type_size = 1;
                break;
            case TYPE::STRING:
                type_size = 4;
                break;
            case TYPE::NEXIST:
                type_size = 0;
                break;
            default:
                type_size = 0;
                break;
        }
    }

    pair<Offset, TYPE> get_var(vector<string>::iterator begin, vector<string>::iterator end) const final; 

    TYPE get_type_value() const {
        return typeName;
    }

    TYPE typeName;
    // void *memory_8; // 8字节内存，存储Standard类型的值
};

class SymRecordType: public SymType {
public:
    SymRecordType(const vector<pair<string, SymType*>> &vars) {
        size_t size = 0;
        size_t a_size, left;
        // cout << "constructor\n";
        for (auto &var : vars) {
            // 获取当前元素的对其大小，align_size
            a_size = var.second->get_align_size();
            if (a_size == 0) {
                // 错误处理
                cout << "Error at SymRecordType: " << var.first << "'s type is not existed";
                continue;
            }
            // cout << var.first << " : original start: " << size << endl;
            // cout << var.first << " : align_size: " << a_size << endl;
            // 设置结构体对齐
            left = size % a_size;
            // 这是加上额外对齐的大小
            size += left == 0 ? 0 : a_size - left;
            // cout << "insert into record: <" << var.first << ", " << size << ">\n";
            // 插入结构体中
            this->record.push_back(make_tuple(var.first, var.second, size));
            // 更新当前总大小
            size += var.second->get_size();
            // 设置该结构体的对齐大小
            align_size = align_size < a_size ? a_size : align_size;
        }
        this->set_size();
    }

    bool equal_to(const SymRecordType &b) const {
        if (this->record.size() != b.record.size()) {
            return false;
        }
        else {
            string name1, name2;
            SymType* pType1, *pType2;
            size_t offset1, offset2;

            for (int i = 0; i < this->record.size(); i++) {
                std::tie(name1, pType1, offset1) = this->record[i];
                std::tie(name2, pType2, offset2) = b.record[i];
                if (name1 != name2 || *pType1 != *pType2 || offset1 != offset2) {
                    return false;
                }
            }
            return true;
        }
    }

    virtual bool operator == (const SymType &b) const override {
        return b.get_type_form() == TypeForm::RECORD && this->equal_to(dynamic_cast<const SymRecordType&>(b));
    }
    virtual TypeForm get_type_form() const override {
        return TypeForm::RECORD;
    }

    void set_align_size() final {
        size_t a_size = 0;
        size_t s;
        for (auto tp : record) {
            s = std::get<1>(tp)->get_align_size();
            a_size = a_size < s ? s : a_size;
        }
        align_size = a_size;
    }

    virtual void set_size() override {
        auto &record_elem = this->record.back();
        type_size = get<2>(record_elem) + get<1>(record_elem)->get_size();
    }
    // 返回结构体中成员的偏移地址和大小
    pair<Offset, TYPE> get_var(vector<string>::iterator begin, vector<string>::iterator end) const final; 

    // 成员名，成员类型， 偏移量
    vector<tuple<string, SymType*, size_t>> record;
};

class SymArrayType: public SymType {
public:
    SymArrayType(SymType *pType, vector<pair<size_t, size_t>>&& dims):
        type(pType), dims(std::move(dims)) {
        this->set_size();
    }

    SymArrayType(SymType *pType, const vector<pair<size_t, size_t>> &_dims):
        type(pType), lost(0), dims(_dims), prod(std::vector<size_t>(dims.size())){
        this->set_size();
        size_t prod_val = type->get_size();
        // 求解偏移量offset最终满足如下规则，注意要求的是开始的地址，即a[1..2]，a[t]的首地址是(t-1) * size
        // f = (\sum_{i=0}^{k} t_i\prod_{j=i+1}^{k}n_j - \sum_{i=0}^{k} low_i\prod_{j=i+1}^{k}n_j) * size
        // 其中k代表dims.size(), n_j代表第j维的元素个数, 即up_j - low_j + 1
        for (int i = dims.size() - 1; i >= 0; i--) {
            // 存储系数
            prod[i] = prod_val;
            lost -= dims[i].first * prod_val;
            prod_val *= dims[i].second - dims[i].first + 1;
        }
    }

    bool equal_to(const SymArrayType& b) const {
        return *(b.type) == *(this->type) && b.dims == this->dims; 
    }

    virtual bool operator == (const SymType &b) const override {
        return b.get_type_form() == TypeForm::ARRAY && this->equal_to(dynamic_cast<const SymArrayType&>(b));
    }
    virtual TypeForm get_type_form () const override {
        return TypeForm::ARRAY;
    }

    void set_align_size() final {
        align_size = type->get_align_size();
    }

    virtual void set_size() override {
        // type_size = len * type->get_size();
        type_size = 0;
        auto elem_size = type->get_size();
        for (auto &dim : dims) {
            type_size += (dim.second - dim.first + 1) * elem_size;
        }
    }

    pair<Offset, TYPE> get_var(vector<string>::iterator begin, vector<string>::iterator end) const final; 
    

    SymType* type;
    size_t lost;
    vector<pair<size_t, size_t>> dims; // 各个维度的范围
    vector<size_t> prod;
};


class Sym_Record{
public:
    string name;  
    string nameInComputer; 
    int line;
    SymRecordType* record_type;
    int get_index(string sub_name);
    TYPE find_member(vector<string>& list, int& index);
};

class Sym_array{
public:
    vector<PII> array_range;
    TYPE typeName;
    //SymRecordType* record_struct;
    string name;
    string type;// standard record
    string nameInComputer;
    int line;
    // int get_index(vector<int>& V);
    int w;
    int C;//下标常量
    vector<int> pos;
    void get_const_index();
    string get_n(int i){
        int low = this->array_range[i].first;
        int high = this->array_range[i].second;
        if(i < low || i > high){
            return "";
        }
        int n = high - low + 1;
        string ans = "n_" + to_string(n);
        return ans;                
    }
    string get_w(){
        string ans = "n_" + to_string(w);
        return ans;
    }
    string get_C(){
        string ans = "n_" + to_string(C);
        return ans;
    }
};

class SymbolTable{
public:
    int line;
    string head;                                   
    ReturnValue returnValue;                       
    vector<Sym_parameter*> parameterList;         
    vector<Sym_constVariable*> constVariableList; 
    vector<Sym_variable*> variableList;           
    //vector<Sym_record*> recordList;

    // 存储在Type记号下声明的类型
    vector<Sym_Record*> recordList;
    /*
    // 类型名和实际类型的映射
    unordered_map<string, shared_ptr<SymType>> typeMap; //typeList
    // 存储几种基础类型(standard type)
    vector<shared_ptr<SymStdType>> stdTypeList;
    shared_ptr<SymStdType> get_std_type(const TYPE &typeName) const {
        return stdTypeList[typeName];
    }
    // 递归地查找typeMap中的类型
    shared_ptr<SymType> find_type(const string& typeName) const;
    // 向本符号表的typeMap中添加新类型
    void add_type(const string& typeName, shared_ptr<SymType>& type);
    // 向本符号表，从已有类型中添加新类型
    void add_type(const string& lval, const string& rval);
    // 以三元组或者string表示的三元组形式表示的record成员
    string get_record_member() const;
    */
    vector<Sym_array*> arrayList;
    vector<SymbolTable *> functionList;            
    vector<SymbolTable *> procedureList;           
    SymbolTable *preSymbolTable;                   
    unordered_map<string, PCI> fastPosition;    

    // find的类似函数定义的参数还要修改!!!!!!
    // PSS findAll(string name, SymbolTable *now);       //这里面包含后面三个 PSS 的第一个 是 t几 第二个 是 类型
    // PSS findFunction(string name, SymbolTable *now);  //找函数
    // PSS findProcedure(string name, SymbolTable *now); //找过程
    string find_return_inname(){
        return this->returnValue.nameInComputer;
    }
    CLASS find_ID(string name);        // 找ID
    CLASS find_all_ID(string name);
    bool rename_head(string name);
    PTS find_ConstVariable_value(string name);
    PTS find_ConstVariable_inname(string name);
    PTS find_left_id(string name);
    PTS find_right_id(string name);
    PTS find_array(string name);
    Sym_array* find_array_ptr(string name);
    PTSI find_record(string name, vector<string>& list);
    bool find_parameter(string name);
    TYPE find_Function(string name, vector<TYPE>& parameter);
    bool find_Procedure(string name, vector<TYPE>& parameter);
    void find_all_parameter(string name, vector<bool>& para_type);
    // PSS findType(string name, SymbolTable *now);      // type的东西有待商榷

    void insert_ConstVariable(string id, int lineNumber, TYPE type, bool isMinus, string value); // 0 是不成功 1 是成功 主要注意 变量重复定义
    void insert_Variable(string id, int lineNumber, TYPE type);
    void insert_Array(string id, int lineNumber, TYPE type, vector<PII>& arrayRangeList);
    //void insert_Array_Record(string id, int lineNumber, SymRecordType* record, vector<PII>& arrayRangeList);
    //bool insert_Array(string id, int lineNumber, vector<PSS>& record_type, vector<PII>& arrayRangeList);
    void insert_record(string id, int lineNumber, SymRecordType* Type);
    void insert_return_value(TYPE type, int line);
    void insert_model_name(string id, int line);
    void insert_parameter(string id, int lineNumber, TYPE type, bool is_reference);
    void insert_function(SymbolTable* sub_symboltable);
    void insert_procedure(SymbolTable* sub_symboltable);

    SymbolTable(){
        preSymbolTable = nullptr;
    }
    ~SymbolTable();
};

#endif